package org.boot.fast.core.mate;

import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.boot.fast.core.mate.entity.ColumnInfo;
import org.boot.fast.core.mate.entity.TableInfo;
import org.boot.fast.core.mate.entity.TableStructure;
import org.boot.fast.util.ObjectUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

@Slf4j
@Service
public class DatabaseMetaService {

    @Resource
    private SqlSessionFactory sqlSessionFactory;

    /**
     * 获取表结构信息
     */
    public TableStructure getTableStructure(String tableName) {
        TableStructure structure = new TableStructure();

        try (SqlSession sqlSession = sqlSessionFactory.openSession()) {
            Connection connection = sqlSession.getConnection();
            DatabaseMetaData metaData = connection.getMetaData();

            // 获取表信息
            structure.setTableInfo(getTableInfo(metaData, tableName));
            // 获取列信息
            structure.setColumns(getColumns(metaData, tableName));
            // 获取主键信息
            structure.setPrimaryKeys(getPrimaryKeys(metaData, tableName));
            if (ObjectUtil.isEmpty(structure.getTableInfo())) return null;
        } catch (SQLException e) {
            log.error("获取表结构信息失败", e);
            throw new RuntimeException("获取表结构信息失败");
        }
        return structure;
    }

    private TableInfo getTableInfo(DatabaseMetaData metaData, String tableName) throws SQLException {
        ResultSet tables = metaData.getTables(null, null, tableName, new String[]{"TABLE"});
        if (tables.next()) {
            TableInfo info = new TableInfo();
            info.setTableName(tables.getString("TABLE_NAME"));
            info.setTableComment(tables.getString("REMARKS"));
            info.setTableSchema(tables.getString("TABLE_SCHEM"));
            return info;
        }
        return null;
    }

    private List<ColumnInfo> getColumns(DatabaseMetaData metaData, String tableName) throws SQLException {
        List<ColumnInfo> columns = new ArrayList<>();
        ResultSet rs = metaData.getColumns(null, null, tableName, null);

        while (rs.next()) {
            ColumnInfo column = new ColumnInfo();
            column.setColumnName(rs.getString("COLUMN_NAME"));
            column.setDataType(rs.getString("TYPE_NAME"));
            column.setIsNullable(rs.getString("IS_NULLABLE"));
            column.setColumnDefault(rs.getString("COLUMN_DEF"));
            column.setColumnComment(rs.getString("REMARKS"));
            columns.add(column);
        }
        return columns;
    }

    private List<String> getPrimaryKeys(DatabaseMetaData metaData, String tableName) throws SQLException {
        List<String> primaryKeys = new ArrayList<>();
        ResultSet rs = metaData.getPrimaryKeys(null, null, tableName);

        while (rs.next()) {
            primaryKeys.add(rs.getString("COLUMN_NAME"));
        }
        return primaryKeys;
    }
}